package services

import (
	"context"
	"gitee.com/igolang/imoney/internal/app/system/entities"
	"gitee.com/igolang/imoney/internal/app/system/entities/constants"
	commonEntities "gitee.com/igolang/imoney/internal/common/entities"
	"gitee.com/igolang/imoney/internal/common/httpResp"
	commonTools "gitee.com/igolang/imoney/internal/common/tools"
	"gitee.com/igolang/imoney/internal/models/dao"
	"gitee.com/igolang/imoney/internal/models/model"
	"gitee.com/igolang/pkg/xutils"
	"github.com/gin-gonic/gin"
	"gorm.io/gen"
)

func (s *role) AllocatedList(ctx *gin.Context, un bool) (*commonEntities.ListResp, error) {
	var req entities.RoleAllocatedPageListReq
	if err := ctx.ShouldBind(&req); err != nil {
		return nil, err
	}
	if req.RoleId == 0 {
		return nil, httpResp.ErrorCode(httpResp.ErrCodeInvalidParams)
	}
	req.Page()
	conds := s.formatAllocatedListConds(req, un)
	total, err := dao.SysUser.Where(conds...).LeftJoin(dao.SysUserRole, dao.SysUserRole.UserID.EqCol(dao.SysUser.UserID)).Distinct(dao.SysUser.UserID).Count()
	if err != nil {
		return nil, err
	}
	result := &commonEntities.ListResp{
		Total: total,
		Rows:  make([]*model.SysUser, 0),
	}
	if total == 0 {
		return result, nil
	}
	rows, err := dao.SysUser.Distinct(
		dao.SysUser.UserID,
		dao.SysUser.UserName,
		dao.SysUser.NickName,
		dao.SysUser.CreateTime,
		dao.SysUser.Email,
		dao.SysUser.Phonenumber,
		dao.SysUser.Status,
	).LeftJoin(dao.SysUserRole, dao.SysUserRole.UserID.EqCol(dao.SysUser.UserID)).Where(conds...).Offset(req.Offset).Limit(req.PageSize).Order(dao.SysUser.UserID.Desc()).Find()
	if err != nil {
		return nil, err
	}
	result.Rows = rows
	return result, nil
}

func (s *role) SelectAll(ctx *gin.Context, cancel bool) error {
	var req struct {
		RoleId  int64  `json:"roleId" form:"roleId"`
		UserIds string `json:"userIds" form:"userIds"`
	}
	if err := ctx.ShouldBind(&req); err != nil {
		return err
	}
	if req.RoleId == 0 || req.UserIds == "" {
		return httpResp.ErrorCode(httpResp.ErrCodeInvalidParams)
	}
	uids := commonTools.String2Int64s(req.UserIds)
	var err error
	if cancel {
		_, err = dao.SysUserRole.Where(dao.SysUserRole.RoleID.Eq(req.RoleId), dao.SysUserRole.UserID.In(uids...)).Delete()
	} else {
		err = dao.Q.Transaction(func(tx *dao.Query) error {
			if _, e := tx.SysUserRole.Where(tx.SysUserRole.RoleID.Eq(req.RoleId), tx.SysUserRole.UserID.In(uids...)).Delete(); e != nil {
				return e
			}
			data := make([]*model.SysUserRole, 0)
			for _, v := range uids {
				if v != 0 {
					data = append(data, &model.SysUserRole{
						UserID: v,
						RoleID: req.RoleId,
					})
				}
			}

			if len(data) == 0 {
				return httpResp.ErrorCode(httpResp.ErrCodeInvalidParams)
			}
			return tx.SysUserRole.CreateInBatches(data, 100)
		})
	}
	if err == nil {
		cctx := ctx.Copy()
		xutils.RecoverGo(func() {
			for _, v := range uids {
				User.LoginUserClean(v)
			}
		}, commonTools.ErrorHandler(context.Background(), "角色授权, req: %v, path:%s", req, cctx.Request.URL.Path))
	}
	return err
}

func (s *role) CancelAuth(ctx *gin.Context) error {
	var req struct {
		RoleId int64 `json:"roleId" form:"roleId"`
		UserId int64 `json:"userId" form:"userId"`
	}
	if err := ctx.ShouldBind(&req); err != nil {
		return err
	}
	if req.RoleId == 0 || req.UserId == 0 {
		return httpResp.ErrorCode(httpResp.ErrCodeInvalidParams)
	}
	_, err := dao.SysUserRole.Where(dao.SysUserRole.RoleID.Eq(req.RoleId), dao.SysUserRole.UserID.Eq(req.UserId)).Delete()
	if err == nil {
		User.LoginUserClean(req.UserId)
	}
	return err
}

func (s *role) formatAllocatedListConds(req entities.RoleAllocatedPageListReq, un bool) []gen.Condition {
	conds := make([]gen.Condition, 0)
	if un {
		conds = append(conds, dao.SysUserRole.RoleID.Neq(req.RoleId))
	} else {
		conds = append(conds, dao.SysUserRole.RoleID.Eq(req.RoleId))
	}
	if req.UserName != "" {
		conds = append(conds, dao.SysUser.UserName.Like(`%`+req.UserName+`%`))
	}
	if req.PhoneNumber != "" {
		conds = append(conds, dao.SysUser.Phonenumber.Like(`%`+req.PhoneNumber+`%`))
	}
	conds = append(conds, dao.SysUser.UserID.Neq(constants.SuperAdminId))
	return conds
}
